using System;
using System.Xml;

namespace stunnware.CRM.Fetch {
   /// <summary>
   /// The FetchLinkEntity represents another entity joined to an already used entity.
   /// </summary>
   public class FetchLinkEntity : FetchEntityBase {
      private string _to;
      private string _from;
      private string _alias;
      private FetchLinkType _linkType;
      
      /// <summary>
      /// Creates a new instance bound to the specified entity.
      /// </summary>
      /// <param name="entityName">The entity name.</param>
      public FetchLinkEntity(string entityName) : base(entityName) {
      }

      /// <summary>
      /// The attribute of the source entity.
      /// </summary>
      public string From {
         get {
            return _from;
         }

         set {
            _from = value;
         }
      }

      /// <summary>
      /// The attribute of the target entity (the one specified in <see cref="FetchEntityBase.EntityName"/>).
      /// </summary>
      public string To {
         get {
            return _to;
         }

         set {
            _to = value;
         }
      }

      /// <summary>
      /// An alias to use instead of the attribute name.
      /// </summary>
      public string Alias {
         get {
            return _alias;
         }

         set {
            _alias = value;
         }
      }

      /// <summary>
      /// The link type (join type).
      /// </summary>
      public FetchLinkType LinkType {
         get {
            return _linkType;
         }

         set{
            _linkType = value;
         }
      }

      /// <summary>
      /// Adds the definition of this class to an XML document.
      /// </summary>
      /// <param name="entityNode"></param>
      internal void AddToFetchDocument(XmlElement entityNode) {

         XmlElement linkedEntityNode = FetchXmlDocument.AddElement(entityNode, "link-entity");
         FetchXmlDocument.AddAttribute(linkedEntityNode, "name", EntityName);

         if (From != null) {
            FetchXmlDocument.AddAttribute(linkedEntityNode, "from", From);
         }

         if (To != null) {
            FetchXmlDocument.AddAttribute(linkedEntityNode, "to", To);
         }

         if (Alias != null) {
            FetchXmlDocument.AddAttribute(linkedEntityNode, "alias", Alias);
         }

         if ((LinkType == FetchLinkType.Inner) || (LinkType == FetchLinkType.Natural) || (LinkType == FetchLinkType.Outer)) {
            FetchXmlDocument.AddAttribute(linkedEntityNode, "link-type", LinkType.ToString().ToLower());
         }

         base.AddElements(linkedEntityNode);
      }

      /// <summary>
      /// Parses the passed xml node and creates a new instance from it.
      /// </summary>
      /// <param name="node"></param>
      /// <returns></returns>
      public static FetchLinkEntity FromXml(XmlNode node) {

         XmlAttribute attr = node.Attributes["name"];

         if (attr == null) {
            throw new XmlException("The name attribute in missing in the entity node.");
         }

         FetchLinkEntity entity = new FetchLinkEntity(attr.Value);
         entity.PopulateFromXml(node);

         attr = node.Attributes["from"];
         if (attr != null) {
            entity.From = attr.Value;
         }

         attr = node.Attributes["to"];
         if (attr != null) {
            entity.To = attr.Value;
         }

         attr = node.Attributes["alias"];
         if (attr != null) {
            entity.Alias = attr.Value;
         }

         attr = node.Attributes["link-type"];
         if (attr != null) {

            switch(attr.Value) {

               case "natural":
                  entity.LinkType = FetchLinkType.Natural;
                  break;

               case "inner":
                  entity.LinkType = FetchLinkType.Inner;
                  break;
            
               case "outer":
                  entity.LinkType = FetchLinkType.Outer;
                  break;
            }
         }

         return entity;
      }
   }

   /// <summary>
   /// The possible link types.
   /// </summary>
   public enum FetchLinkType {
      /// <summary>
      /// If default is specified, the link type will not be included in the FetchXML query.
      /// </summary>
      Default,

      /// <summary>
      /// A JOIN
      /// </summary>
      Natural,

      /// <summary>
      /// An INNER JOIN
      /// </summary>
      Inner,

      /// <summary>
      /// An OUTER JOIN
      /// </summary>
      Outer
   }
}


/*
	<ElementType name='linked-entity' content='eltOnly' model='closed' order='many'>
		<element type='filter' minOccurs='0' maxOccurs='1' />
	</ElementType>

 */